/*
 * Created on May 8, 2004
 */
package dk.aiszone.lang.autosource.generatorobjects;

import java.util.ArrayList;
import java.util.List;

import dk.aiszone.lang.autosource.generatorobjects.helpers.ImportsList;
import dk.aiszone.lang.autosource.generatorobjects.interfaces.DeclarableObject;
import dk.aiszone.lang.autosource.generatorobjects.interfaces.GeneratorObject;

/**
 * The <code>Variable</code> class represent a &quot;global&quot; variable in a <code>AbstractBody</code>.
 * 
 * @author <a href="mailto:ais@mail.dk">Ais</a>
 * @since 1.0
 * @version 1.0
 */
public class Variable extends GeneratorObject implements Cloneable, Comparable<Variable>, DeclarableObject {

    private List<Annotation> annotations;
    private Declaration declaration;
    private ImportsList imports;
    private String initialization;
    private JavaDoc javaDoc;
    private String name;
    private StaticArea staticArea;
    private Class type;

    /**
     * Default constructor for the <code>Variable</code> class.<br>
     * Using this constructor requires the user to set the <code>Declaration</code>, the type and the name of the <code>Variable</code>.
     * 
     * @see #setDeclaration(Declaration)
     * @see #setType(Class)
     * @see #setName(String)
     */
    public Variable() {
        super();
        this.imports = new ImportsList();
        this.annotations = new ArrayList<Annotation>();
    }

    /**
     * Constructor for the <code>Variable</code> class.
     * 
     * @param declaration
     *            The <code>Declaration</code> of the <code>Variable</code>
     * @param type
     *            The type of <code>Variable</code>
     * @param name
     *            The name of the <code>Variable</code>
     */
    public Variable(Declaration declaration, Class type, String name) {
        this(declaration, type, name, (String)null);
    }

    /**
     * Constructor for the <code>Variable</code> class.
     * 
     * @param declaration
     *            The <code>Declaration</code> of the <code>Variable</code>
     * @param type
     *            The type of <code>Variable</code>
     * @param name
     *            The name of the <code>Variable</code>
     * @param initialization
     *            The initialization string of the <code>Variable</code>.<br>
     *            The supplied initialization string will be appended the <code>Variable</code><br>
     *            declaration with an prefixed &quot;=&quot;-character.
     */
    public Variable(Declaration declaration, Class type, String name, String initialization) {
        this();
        this.declaration = declaration;
        this.name = name;
        this.type = type;
        this.initialization = initialization;
    }

    @Override
    public void addAnnotation(Annotation annotation) {
        imports.addAll(annotation.getNeededImports());
        annotations.add(annotation);
    }

    /**
     * Adds an <code>Import</code> to the variable.
     * 
     * @param _import
     *            <code>Import</code> needed by the variable.
     */
    public void addNeededImport(Import _import) {
        imports.addImport(_import);
    }

    @Override
    public Object clone() {
        Variable clone = new Variable((Declaration)declaration.clone(), (Class)type.clone(), name, initialization);
        if (this.staticArea != null) {
            clone.staticArea = (StaticArea)this.staticArea.clone();
        }
        return clone;
    }

    public int compareTo(Variable other) {
        int res = declaration.compareTo(other.declaration);
        if (res == 0) {
            return name.compareTo(other.name);
        }
        return res;
    }

    @Override
    public List<Annotation> getAnnotations() {
        return annotations;
    }

    /**
     * Retrieve the <code>Declaration</code> of the <code>Variable</code>.
     * 
     * @return The variable declaration - or <code>null</code> if unset.
     */
    public Declaration getDeclaration() {
        return declaration;
    }

    /**
     * Retrieve the initialization string of the <code>Variable</code>
     * 
     * @return The initialization of the <code>Variable</code>
     */
    public String getInitialization() {
        return initialization;
    }

    /**
     * Retrieve the <code>JavaDoc</code> of the <code>Variable</code>
     * 
     * @return The declared <code>JavaDoc</code> object.
     */
    public JavaDoc getJavaDoc() {
        if (javaDoc == null) {
            setJavaDoc(new JavaDoc());
        }

        return javaDoc;
    }

    /**
     * Retrieve the name of the <code>Variable</code>
     * 
     * @return The variable name - or <code>null</code> if unset.
     */
    public String getName() {
        return name;
    }

    /**
     * Retrieve a <code>ImportList</code> containing all the <code>Imports</code> needed by the <code>Variable</code>.
     * 
     * @return The needed <code>Imports</code>.
     */
    public ImportsList getNeededImports() {
        if (type.requiresImport()) {
            imports.addImports(type.toImports());
        }
        if (staticArea != null) {
            imports.addAll(staticArea.getNeededImports());
        }

        return imports;
    }

    /**
     * Retrieve the <code>StaticArea</code> part of the the variable declaration.
     * 
     * @return The <code>StaticArea</code> declaration - or <code>null</code> is unset.
     */
    public StaticArea getStaticArea() {
        return staticArea;
    }

    /**
     * Retrieve the type of the <code>Variable</code>
     * 
     * @return <code>Class</code> representing the type of the <code>Variable</code>.
     */
    public Class getType() {
        return type;
    }

    /**
     * Set the <code>Declaration</code> of the <code>Variable</code>.
     * 
     * @param declaration
     *            The variable declaration - or <code>null</code> to unset.
     */
    public void setDeclaration(Declaration declaration) {
        this.declaration = declaration;
    }

    /**
     * Set the initialization of the <code>Variable</code>.
     * 
     * @param initialization
     *            The initialization string of the <code>Variable</code>.<br>
     *            The supplied initialization string will be appended the <code>Variable</code><br>
     *            declaration with an prefixed &quot;=&quot;-character.
     */
    public void setInitialization(String initialization) {
        this.initialization = initialization;
    }

    /**
     * Set the <code>JavaDoc</code> of the <code>Variable</code>.
     * 
     * @param javaDoc
     *            The documentation of the <code>Variable</code>
     */
    public void setJavaDoc(JavaDoc javaDoc) {
        this.javaDoc = javaDoc;
    }

    /**
     * Set the name of the <code>Variable</code>
     * 
     * @param name
     *            The variable name - or <code>null</code> to unset.
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Set the <code>StaticArea</code> of the <code>Variable</code>
     * 
     * @param staticArea
     *            Static declaration of the variable - or <code>null</code> to unset.
     */
    public void setStaticArea(StaticArea staticArea) {
        this.staticArea = staticArea;
    }

    /**
     * Set the type of the <code>Variable</code>
     * 
     * @param type
     *            The <code>Class</code> representing the type of the <code>Variable</code>.
     */
    public void setType(Class type) {
        this.type = type;
    }
}